package com.zkjl.protect_business.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import cn.hutool.json.JSONUtil;
import com.zkjl.protect_business.common.BaseException;
import com.zkjl.protect_business.common.Status;
import com.zkjl.protect_business.common.UserThreadLocal;
import com.zkjl.protect_business.dto.NoticeDTO;
import com.zkjl.protect_business.dto.PageBaseDTO;
import com.zkjl.protect_business.dto.SortDTO;
import com.zkjl.protect_business.entity.*;
import com.zkjl.protect_business.repository.NoticeRecordRepository;
import com.zkjl.protect_business.repository.NoticeRepository;
import com.zkjl.protect_business.repository.OrganizationRepository;
import com.zkjl.protect_business.service.FileService;
import com.zkjl.protect_business.service.LogService;
import com.zkjl.protect_business.service.NoticeRecordService;
import com.zkjl.protect_business.service.NoticeService;
import com.zkjl.protect_business.utils.QueryUtil;
import com.zkjl.protect_business.vo.statistic.GroupVO;
import com.zkjl.protect_business.vo.NoticeVO;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.*;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.zkjl.protect_business.common.Consts.*;

@Service
public class NoticeServiceImpl implements NoticeService {

    @Autowired
    ModelMapper modelMapper;
    @Autowired
    NoticeRepository noticeRepository;
    @Autowired
    OrganizationRepository organizationRepository;
    @Autowired
    NoticeRecordRepository noticeRecordRepository;
    @Autowired
    ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Autowired
    NoticeRecordService noticeRecordService;

    @Autowired
    LogService logService;
    @Autowired
    FileService fileService;

    @Override

    public Notice save(NoticeDTO noticeDTO) {

        Notice notice = modelMapper.map(noticeDTO, Notice.class);
        Digester md5 = new Digester(DigestAlgorithm.MD5);
        String id = md5.digestHex(JSONUtil.toJsonStr(notice));
        notice.setId(id);
        notice.setStatus(NOTICE_STATUS_ONGOING);
        notice.setBaseInfo();
        Notice save = noticeRepository.save(notice);

        //给文件设置是否允许下载
        Boolean isdownload = notice.getIsdownload();
        if (isdownload != null && !isdownload) {
            List<String> attachmentIds = save.getAttachmentIds();
            if (CollUtil.isNotEmpty(attachmentIds)) {
                attachmentIds.stream().forEach(attachmentId ->{
                    fileService.updateIsDownload(attachmentId, false);
                });
            }

        }

        //保存每个单位的读取记录
        List<String> orgIds = noticeDTO.getOrgIds();
        if (CollUtil.isEmpty(orgIds)) {
            throw new BaseException(Status.BAD_REQUEST.getCode(), "通知单位不能为空！");
        }
        Iterable<Organization> organizations = organizationRepository.findAllById(orgIds);
        if (CollUtil.isNotEmpty(organizations)) {

            organizations.forEach(organization -> {
                String orgName = organization.getOrgName();
                String orgId = organization.getId();

                NoticeRecord noticeRecord = new NoticeRecord();
                noticeRecord.setId(IdUtil.simpleUUID());
                noticeRecord.setNoticeId(id);
                noticeRecord.setIsRead("未读");
                noticeRecord.setOrgId(orgId);
                noticeRecord.setOrgName(orgName);
                noticeRecordRepository.save(noticeRecord);
            });
        }

        logService.save("文件通知", notice.getName(), OPERATION_ADD);

        return save;
    }

    @Override
    public PageImpl page(PageBaseDTO pageBaseDTO, SortDTO sortDTO, String status) {

        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder qb = QueryBuilders.boolQuery();

        String orgId = UserThreadLocal.getOrgId();

        //只能查看自己发起的和自己接收的,管理员能查看全部
        String userRole = UserThreadLocal.getUserRole();
        if (!ADMIN.equals(userRole)) {
            qb.should(new TermsQueryBuilder("org_ids", orgId));
            qb.should(new TermsQueryBuilder("create_org_id", orgId));
        }

        if (StringUtils.isNotEmpty(status)) {
            qb.filter(new QueryStringQueryBuilder(status).field("status").defaultOperator(Operator.AND));
        }

        Pageable pageable = QueryUtil.build(qb, queryBuilder, pageBaseDTO, sortDTO, Notice.class);

        queryBuilder.withQuery(qb);

        SearchHits<Notice> search1 = elasticsearchRestTemplate.search(queryBuilder.build(), Notice.class);
        List<Notice> collect = search1.stream().map(SearchHit::getContent).collect(Collectors.toList());

        //处理已读未读统计
        List<NoticeVO> collect1 = collect.stream().map(notice -> {

            String id = notice.getId();
            Long readNum = noticeRecordService.getReadNum(id, "已读");
            Long unReadNum = noticeRecordService.getReadNum(id, "未读");
            NoticeVO noticeVO = modelMapper.map(notice, NoticeVO.class);

            //处理通知状态
            Long endTime = noticeVO.getEndTime();
            if (endTime != null && System.currentTimeMillis() > endTime) {
                noticeVO.setStatus(NOTICE_STATUS_OVER);
            }

            noticeVO.setReadNum(readNum);
            noticeVO.setUnReadNum(unReadNum);
            return noticeVO;
        }).collect(Collectors.toList());

        long total = search1.getTotalHits();

        PageImpl page = new PageImpl(collect1, pageable, total);

        return page;
    }

    @Override
    public Boolean del(String id) {

        Notice notice = get(id);
        String name = notice.getName();
        logService.save("文件通知", name, OPERATION_DEL);

        noticeRepository.deleteById(id);
        return true;
    }

    @Override
    public Notice get(String id) {

        Optional<Notice> repository = noticeRepository.findById(id);
        if (!repository.isPresent()) {
            throw new BaseException(Status.DATA_NOT_EXIST.getCode(), "未找到文件通知信息！");
        }
        Notice notice = repository.get();


        return notice;
    }

    @Override
    @Deprecated
    public void download(HttpServletResponse response, String noticeId, String fileId) throws IOException {
        Optional<Notice> repository = noticeRepository.findById(noticeId);
        if (!repository.isPresent()) {
            throw new BaseException(Status.DATA_NOT_EXIST.getCode(), "未找到该文件通知！");
        }
        Notice notice = repository.get();
        Boolean isdownload = notice.getIsdownload();
        if (!isdownload) {
            throw new BaseException(Status.BAD_REQUEST.getCode(), "该通知的文件不能下载！");
        }

        fileService.download(response, fileId);
    }


}
